<template>
  <!-- 检索栏 -->
  <a-form class="smart-query-form" :model="queryParams" ref="queryRef" layout="inline" v-show="showSearch"
    :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
    <a-row class="smart-query-form-row">
      <a-form-item label="模型标识" name="modelId" class="smart-query-form-item">
        <a-input v-model:value="queryParams.modelId" placeholder="请输入模型标识" allowClear @pressEnter="handleQuery" />
      </a-form-item>
      <a-form-item label="模型名称" name="modelName" class="smart-query-form-item">
        <a-input v-model:value="queryParams.modelName" placeholder="请输入模型名称" allowClear @pressEnter="handleQuery" />
      </a-form-item>
      <a-form-item label="流程分类" name="category" class="smart-query-form-item">
        <a-select v-model:value="queryParams.category" placeholder="流程分类" allowClear style="width: 240px">
          <a-select-option v-for="item in flowCategory" :key="item.code" :value="item.code">
            {{ item.name }}
          </a-select-option>
        </a-select>
      </a-form-item>

      <a-form-item class="smart-query-form-item">
        <a-button-group>
          <a-button type="primary" @click="handleQuery" v-privilege="'flow:flow_model:list'">
            <template #icon>
              <SearchOutlined />
            </template>
            查询
          </a-button>
          <a-button @click="resetQuery" v-privilege="'flow:flow_model:list'">
            <template #icon>
              <ReloadOutlined />
            </template>
            重置
          </a-button>
        </a-button-group>
      </a-form-item>
    </a-row>
  </a-form>

  <a-card size="small" :bordered="false" :hoverable="true">
    <a-row class="smart-table-btn-block">
      <div class="smart-table-operate-block">
        <a-button type="primary" @click="handleAdd">
          <template #icon>
            <PlusOutlined />
          </template>
          新增
        </a-button>

        <a-button type="primary" :disabled="selectedRowKeyList.length != 1" @click="handleUpdate">
          <template #icon>
            <EditOutlined />
          </template>
          修改
        </a-button>

        <a-button type="primary" danger :disabled="selectedRowKeyList.length === 0" @click="handleDelete">
          <template #icon>
            <DeleteOutlined />
          </template>
          删除
        </a-button>
      </div>
      <div class="smart-table-setting-block">
        <TableOperator v-model="columns" :tableId="TABLE_ID_CONST.BUSINESS.FLOW.MODEL" :refresh="getList" />
      </div>
    </a-row>

    <a-table size="small" :dataSource="modelList" :pagination="false" rowKey="modelId"
      :row-selection="{ selectedRowKeys: selectedRowKeyList, onChange: onSelectChange }">
      <a-table-column title="模型名称" dataIndex="modelName" align="center" />
      <a-table-column title="流程分类" dataIndex="category" align="center" />
      <a-table-column title="版本" dataIndex="version" align="center">
        <template #default="{ text }">
          <a-tag>v{{ text }}</a-tag>
        </template>
      </a-table-column>
      <a-table-column title="模型描述" dataIndex="description" align="center" />
      <a-table-column title="创建时间" dataIndex="createTime" align="center" width="180">
        <template #default="{ text }">
          <span>{{ parseTime(text, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
        </template>
      </a-table-column>
      <a-table-column title="操作" align="center" width="220">
        <template #default="{ record }">
          <a-space>
            <a-button type="link" @click="handleUpdate(record)">
              <template #icon>
                <EditOutlined />
              </template>
              修改
            </a-button>
            <a-button type="link" @click="handleDesign(record)">
              <template #icon>
                <ToolOutlined />
              </template>
              设计
            </a-button>
            <a-dropdown>
              <a-button type="link">
                更多
                <DownOutlined />
              </a-button>
              <template #overlay>
                <a-menu>
                  <a-menu-item key="deploy" @click="handleDeploy(record)">
                    <template #icon>
                      <PlayCircleOutlined />
                    </template>
                    部署
                  </a-menu-item>
                  <!-- <a-menu-item key="field" @click="handleFieldMaintenance(record)">
                    <template #icon><FieldBinaryOutlined /></template>
                    设置字段
                  </a-menu-item> -->
                  <a-menu-item key="history" @click="handleHistory(record)">
                    <template #icon>
                      <HistoryOutlined />
                    </template>
                    历史
                  </a-menu-item>
                  <a-menu-item key="delete" @click="handleDelete(record)">
                    <template #icon>
                      <DeleteOutlined />
                    </template>
                    删除
                  </a-menu-item>
                </a-menu>
              </template>
            </a-dropdown>
          </a-space>
        </template>
      </a-table-column>
    </a-table>

    <div class="smart-query-table-page">
      <a-pagination showSizeChanger showQuickJumper show-less-items :pageSizeOptions="PAGE_SIZE_OPTIONS"
        :defaultPageSize="queryForm.pageSize" v-model:current="queryForm.pageNum" v-model:pageSize="queryForm.pageSize"
        :total="total" @change="getList" @showSizeChange="getList" :show-total="(total) => `共${total}条`" />
    </div>
  </a-card>
  <!-- 流程图 -->
  <a-modal :title="processView.title" v-model:open="processView.open" width="80%" :footer="null" :destroyOnClose="true">
    <WorkflowView :bpmnXml="processView.bpmnXml" style="height: 90vh" />
  </a-modal>

  <!-- 流程设计界面-->
  <a-modal :title="designView.title" v-model:open="designView.open" :width="'100%'" :footer="null"
    :destroyOnClose="true" :style="{ top: '20px' }">
    <WorkflowVerDesigner :id="designView.modelId" :bpmnXml="designView.bpmnXml" style="height: 90vh" />
  </a-modal>

  <!-- 添加或修改流程模型对话框 -->
  <a-modal :title="title" v-model:open="open" width="500px" @ok="submitForm" @cancel="cancel">
    <a-form ref="modelRef" :model="form" :rules="rules" :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
      <a-form-item label="模型名称" name="modelName">
        <a-input v-model:value="form.modelName" placeholder="请输入模型名称" />
      </a-form-item>
      <a-form-item label="流程分类" name="category">
        <a-select v-model:value="form.category" placeholder="流程分类" allowClear style="width: 240px">
          <a-select-option v-for="item in flowCategory" :key="item.code" :value="item.code">
            {{ item.name }}
          </a-select-option>
        </a-select>
      </a-form-item>
      <a-form-item label="模型描述" name="description">
        <a-textarea v-model:value="form.description" placeholder="请输入模型描述" />
      </a-form-item>
    </a-form>
  </a-modal>

  <!-- 历史记录对话框 -->
  <a-modal title="模型历史" v-model:open="history.open" width="70%" :footer="null">
    <a-table :dataSource="historyListData" :pagination="false" :rowSelection="{ selectedRowKeys: ids, onChange: handleSelectionChange }">
      <a-table-column title="模型标识" dataIndex="modelKey" align="center" :ellipsis="true" />
      <a-table-column title="模型名称" align="center" :ellipsis="true">
        <template #default="{ record }">
          <a-button type="link" @click="handleProcessView(record)">
            {{ record.modelName }}
          </a-button>
        </template>
      </a-table-column>
      <a-table-column title="流程分类" dataIndex="category" align="center" :formatter="categoryFormat" />
      <a-table-column title="模型版本" dataIndex="version" align="center">
        <template #default="{ text }">
          <a-tag>v{{ text }}</a-tag>
        </template>
      </a-table-column>
      <a-table-column title="描述" dataIndex="description" align="center" :ellipsis="true" />
      <a-table-column title="创建时间" dataIndex="createTime" align="center" width="180" />
      <a-table-column title="操作" align="center" width="180">
        <template #default="{ record }">
          <a-space>
            <a-button type="link" @click="handleDeploy(record)">
              <template #icon>
                <PlayCircleOutlined />
              </template>
              部署
            </a-button>
            <a-button type="link" @click="handleLatest(record)">
              设为最新
            </a-button>
          </a-space>
        </template>
      </a-table-column>
    </a-table>
    <div class="smart-query-table-page">
      <a-pagination showSizeChanger showQuickJumper show-less-items :pageSizeOptions="PAGE_SIZE_OPTIONS"
        :defaultPageSize="historyQuerForm.pageSize" v-model:current="historyQuerForm.pageNum" v-model:pageSize="historyQuerForm.pageSize"
        :total="historyTotal" @change="getHistoryList" @showSizeChange="getHistoryList" :show-total="(historyTotal) => `共${historyTotal}条`" />
    </div>
  </a-modal>

  <XmlEditor v-model:open="previewVisible" :code="previewCode" @confirm="handleUpdateXml" />
</template>

<script setup name="Model">
import { modelApi } from "/@/api/business/flowable/model";
import { categoryApi } from "/@/api/business/flowable/category";
import WorkflowView from "/@/components/business/flowable/bpmn/view.vue";
import WorkflowVerDesigner from "/@/components/business/flowable/bpmn/designer.vue";
import XmlEditor from "/@/components/common/XmlEditor.vue";
import { message, Modal } from "ant-design-vue";
import { getCurrentInstance, ref, toRefs, reactive } from "vue";
import InitBPMNXml from '/@/assets/bpmn/holiday-request.bpmn20.xml?raw'
import EmptyBPMNXml from '/@/assets/bpmn/empty.bpmn20.xml?raw'
import { smartSentry } from '/@/lib/smart-sentry';
import { TABLE_ID_CONST } from '/@/constants/support/table-id-const';
import TableOperator from '/@/components/support/table-operator/index.vue';
import { PAGE_SIZE_OPTIONS } from '/@/constants/common-const';
import { SmartLoading } from '/@/components/framework/smart-loading';
import { parseTime } from "/@/components/common/util";
import _ from 'lodash';
import {
  SearchOutlined,
  ReloadOutlined,
  PlusOutlined,
  EditOutlined,
  DeleteOutlined,
  DownOutlined,
  PlayCircleOutlined,
  HistoryOutlined,
  ToolOutlined
} from '@ant-design/icons-vue';

const { proxy } = getCurrentInstance();
const modelList = ref([]);
const open = ref(false);
const showSearch = ref(true);
const ids = ref([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const flowCategory = ref([]);
const insertFlag = ref(true);
const previewVisible = ref(false);
const previewCode = ref('');

const data = reactive({
  form: {},
  queryParams: {
    pageNum: 1,
    pageSize: 10,
    modelId: null,
    modelName: null,
    modelKey: null,
    category: null,
    version: null,
    formType: null,
    formId: null,
    description: null,
    createTime: null,
    bpmnXml: null,
    content: null
  },

  rules: {
  },
  processView: {
    title: '',
    open: false,
    index: undefined,
    xmlData: "",
  },
  queryHistoryParams: {
    pageNum: 1,
    pageSize: 10,
    modelKey: null
  },
  designView: {
    title: '',
    open: false,
    modelId: undefined,
    bpmnXml: ''
  },
  history: {
    open: false,
    loading: false
  },
  historyListData: [],
  historyTotal: 0
});
// 查询表单form
const queryForm = reactive(_.cloneDeep(data.queryParams));
const historyQuerForm = reactive(_.cloneDeep(data.queryHistoryParams))

// ---------------------------- 表格列 ----------------------------

const columns = ref([]);

const { queryParams, form, rules, processView, queryHistoryParams, designView, history, historyListData, historyTotal, fields } = toRefs(data);

/** 查询流程模型列表 */
async function getList() {
  SmartLoading.show()
  try {
    let flowModel = await modelApi.listModel(queryForm)
    modelList.value = flowModel.data.rows;
    total.value = flowModel.data.total;
  } catch (e) {
    smartSentry.captureError(e);
  } finally {
    SmartLoading.hide()
  }
}

async function getFlowCategory() {
  try {
    // 这里强制搜索大小为65536，否则查询的结果只返回默认的前10个
    let categoryModel = await categoryApi.listCategory({pageSize: 65536})
    flowCategory.value = categoryModel.data.rows
  } catch (e) {
    smartSentry.captureError(e)
  }
}

// 取消按钮
function cancel() {
  open.value = false;
  reset();
}

// 表单重置
function reset() {
  form.value = {
    modelId: null,
    modelName: null,
    modelKey: null,
    category: null,
    version: null,
    formType: null,
    formId: null,
    description: null,
    createTime: null,
    bpmnXml: null,
    content: null
  };
  // proxy.resetForm("modelRef");
}

/** 搜索按钮操作 */
function handleQuery() {
  queryParams.value.pageNum = 1;
  getList();
}

/** 重置按钮操作 */
function resetQuery() {
  proxy.resetForm("queryRef");
  handleQuery();
}


// 选择表格行
const selectedRowKeyList = ref([]);

function onSelectChange(selectedRowKeys) {
  selectedRowKeyList.value = selectedRowKeys;
}


// 多选框选中数据
function handleSelectionChange(selection) {
  ids.value = selection.map(item => item.modelId);
  single.value = selection.length != 1;
  multiple.value = !selection.length;
}

/** 新增按钮操作 */
function handleAdd() {
  reset();
  //初始化模型标识
  let timestamp = (new Date()).valueOf();
  form.value = {
    modelId: 'flowable_' + timestamp,
    modelName: 'business_' + timestamp,
    modelKey: 'process_' + timestamp
  }
  insertFlag.value = true;
  open.value = true;
  title.value = "添加流程模型";
}

/** 修改按钮操作 */
async function handleUpdate(row) {
  reset();
  const _modelId = selectedRowKeyList.value[0] || row.modelId
  try {
    let flowModel = await modelApi.getModel(_modelId)
    insertFlag.value = false;
    form.value = flowModel.data;
    open.value = true;
    title.value = "修改流程模型";
  } catch (e) {
    smartSentry.captureError(e)
  }
}

/** 提交按钮 */
function submitForm() {
  proxy.$refs["modelRef"].validate().then(async valid => {
    if (valid) {
      try {
      if (!insertFlag.value) {
          await modelApi.updateModel(form.value)
          message.success("修改成功");
      } else {
          await modelApi.addModel(form.value)
          message.success("新增成功");
      }
    } catch (e) {
          smartSentry.captureError(e)
        } finally {
          open.value = false;
          getList();
        }
    }
  });
}

/** 删除按钮操作 */
function handleDelete(row) {
  let deleteIds = selectedRowKeyList.value
  if (row.modelId) {
    deleteIds = row.modelId
  }
  Modal.confirm({
    title: '提示',
    content: '确定要删除选中的流程模型吗?',
    okText: '删除',
    okType: 'danger',
    onOk() {
      if(batchDelete(deleteIds)) {
        if(!row.modelId) {
          selectedRowKeyList.value = []
        }
      }
    },
    cancelText: '取消',
    onCancel() { },
  });
}

async function batchDelete(deleteIds) {
  try {
    SmartLoading.show();
    await modelApi.delModel(deleteIds);
    message.success('删除成功');
    getList();
    return true
  } catch (e) {
    smartSentry.captureError(e);
    return false
  } finally {
    SmartLoading.hide();
  }
}

/** 设计按钮操作 */
async function handleDesign(row) {
  const _modelId = row.modelId
  try {
    let flowModel = await modelApi.getModel(_modelId)
    let xml = '';
    if (flowModel.data.bpmnXml != '' && typeof (flowModel.data.bpmnXml) != "undefined") {
      xml = flowModel.data.bpmnXml.replaceAll('\\"', '"')
        .replaceAll('\\n', '')
    } else {
      xml = InitBPMNXml.replaceAll('{{PROCESS_ID}}', flowModel.data.modelKey)
        .replaceAll('{{PROCESS_NAME}}', flowModel.data.modelName)
        .replaceAll('{{START_EVENT_ID}}', 'StartEvent_' + Math.random().toString(36).replaceAll('0.', ''))
    }
    designView.value = {
      modelId: _modelId,
      open: true,
      title: '流程图设计',
      bpmnXml: xml
    }
  } catch (e) {
    smartSentry.captureError(e)
  }
}
/** 部署按钮操作 */
async function handleDeploy(row) {
  try {
    let response = await modelApi.depolyModel(row.modelId)
    if (response.ok) {
      message.success("部署成功!");
    } else {
      message.error('部署失败!');
    }
  } catch (e) {
    smartSentry.captureError(e)
  }
}
/** 流程图查看按钮操作 */
async function handleProcessView(row) {
  const _modelId = row.modelId
  try {
    let flowModel = await modelApi.getModelXml(_modelId)
    let xml = '';
    if (flowModel.data != '' && typeof (flowModel.data) != "undefined") {
      xml = flowModel.data.replaceAll('\\"', '"')
        .replaceAll('\\n', '')
    } else {
      xml = EmptyBPMNXml;
    }
    processView.value = {
      modelId: _modelId,
      open: true,
      title: '流程图',
      bpmnXml: xml
    }
  } catch (e) {
    smartSentry.captureError(e)
  }
}
/** 查看历史按钮操作 */
function handleHistory(row) {
  reset();
  const _modelId = row.modelId
  data.history.open = true;
  historyQuerForm.modelKey = row.modelKey;
  getHistoryList();
}
async function getHistoryList() {
  SmartLoading.show()
  try {
    let flowModel = await modelApi.historyList(historyQuerForm)
    data.historyTotal = flowModel.data.total;
    data.historyListData = flowModel.data.rows;
  } catch (e) {
    smartSentry.captureError(e)
  } finally {
    SmartLoading.hide()
  }
}
/** 设为最新版 */
function handleLatest(row) {
  Modal.confirm({
    title: '提示',
    content: '是否确认将此版本设为最新？',
    onOk() {
      data.history.loading = true;
      modelApi.latestModel({
        modelId: row.modelId
      }).then(response => {
        if (response.code == 200) {
          message.success("设置成功!");
        } else {
          message.error("设置失败!");
        }
        data.history.open = false;
        getList();
        message.success(response.msg);
      }).finally(() => {
        data.history.loading = false;
      })
    }
  })
}
/**字段设置*/
function handleFieldMaintenance(row) {

}
/**
 * 翻译分类编码
 * @param row
 * @param column
 * @returns {*|string}
 */
function categoryFormat(row, column) {
  return flowCategory.value.find(k => k.code === row.category)?.name ?? '';
}

/** 预览XML按钮操作 */
async function handlePreviewXml() {
  if (!bpmnModeler.value) {
    return
  }
  loading.value = true
  const { xml } = await bpmnModeler.value.saveXML({ format: true })
  previewCode.value = xml
  previewVisible.value = true
  loading.value = false
}

/** 更新XML */
function handleUpdateXml(xml) {
  importXML(xml)
  previewVisible.value = false
}

getList();
getFlowCategory();
</script>
